package com.yunban.project.api.text_check.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.yunban.project.api.text_check.domain.CorrectionConfig;
import com.yunban.project.api.text_check.dto.XunFeiResponse;
import com.yunban.project.api.text_check.service.CorrectionService;
import com.yunban.project.api.text_check.utils.CorrectUtils;
import jakarta.validation.Payload;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.base.common.exception.BusinessException;
import okhttp3.HttpUrl;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author: lijiajun
 * @date: 2024-11-20
 * @version: 1.0
 */
@Slf4j
@Service("xunFeiCorrectionService")
public class XunFeiCorrectionServiceImpl implements CorrectionService {

    public static final Gson gson = new Gson();

    @Override
    public String correction(String text, CorrectionConfig config, String taskId) {
        CorrectUtils.printStartTime(config.getCode());
        try {
            // 获取鉴权链接
            String url = getAuthUrl(String.format("https://%s%s", config.getHost(), config.getUrlPath()), config.getApiKey(), config.getApiSecret());
            String requestJson = getRequestJson(text, config.getAppId());
            String backResult = doPostJson(url, requestJson);
            log.info("文本纠错返回结果：{}", backResult);
            JsonParse jsonParse = gson.fromJson(backResult, JsonParse.class);
            Header header = jsonParse.header;
            if (ObjectUtils.isEmpty(header)) {
                String message = ObjectUtils.isEmpty(jsonParse.message) ? "接口调用失败，请联系管理员" : jsonParse.message;
                throw new BusinessException(message);
            }
            if (header.code != 0) {
                throw new BusinessException(header.message);
            }
            String base64Decode = new String(Base64.getDecoder().decode(jsonParse.payload.result.text), StandardCharsets.UTF_8);
            log.info("text字段base64解码后纠错信息：{}", base64Decode);
            // string to map
            JSONObject jsonObject = JSON.parseObject(base64Decode);
            // 往 jsonObject 添加 text 字段
            jsonObject.put("text", text);
            log.info("xunfei text correction result:{}", JSON.toJSONString(jsonObject));
            // 只返回正确文本
            return this.correctionTextJsonParse(text, jsonObject);
        } catch (Exception ex) {
            log.error("文本纠错异常", ex);
            log.error("class:【{}】 method:【{}】 message:【{}】", this.getClass().getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), ex.getMessage());
            return null;
        } finally {
            CorrectUtils.printEndTime(config.getCode());
        }
    }

    public String correctionTextJsonParse(String originalText, Map<String, Object> result) {
        // 循环 result, 将需要的数据转为 List
        List<XunFeiResponse> resultList = new ArrayList<>();
        for (Map.Entry<String, Object> entry : result.entrySet()) {
            Object value = entry.getValue();
            if (value instanceof List) {
                JSONArray jsonArray = (JSONArray) value;
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONArray r = jsonArray.getJSONArray(i);
                    if (!CollectionUtils.isEmpty(r)) {
                        XunFeiResponse xunFeiResponse = new XunFeiResponse();
                        xunFeiResponse.setPos(r.getInteger(0));
                        xunFeiResponse.setCur(r.getString(1));
                        xunFeiResponse.setCorrect(r.getString(2));
                        xunFeiResponse.setDescription(r.getString(3));
                        resultList.add(xunFeiResponse);
                    }
                }
            }
        }

        // 返回处理后的文本
        StringBuilder correctedText = new StringBuilder(originalText);

        // 按照位置从大到小排序，避免替换时影响后续位置
        resultList.sort((r1, r2) -> Integer.compare(r2.getPos(), r1.getPos()));

        // 替换
        for (XunFeiResponse r : resultList) {
            int pos = r.getPos();
            String cur = r.getCur();
            String correct = r.getCorrect();

            // 检查当前字符是否匹配
            String currentStr = correctedText.substring(pos, pos + cur.length());
            if (!currentStr.equals(cur)) {
                throw new RuntimeException("文本纠错结果与原文不一致");
            }
            // 替换字符
            correctedText.replace(pos, pos + cur.length(), correct);
        }
        log.info("文本纠错后结果：{}", correctedText);
        return correctedText + "----固定语法----一级----无";
    }

    public String getRequestJson(String text, String appId) {
        return "{\n" + "  \"header\": {\n" + "    \"app_id\": \"" + appId + "\",\n" +
                //"    \"uid\": \"XXXXX\",\n" +
                "    \"status\": 3\n" + "  },\n" + "  \"parameter\": {\n" + "    \"s9a87e3ec\": {\n" +
                //"    \"res_id\": \"XXXXX\",\n" +
                "      \"result\": {\n" + "        \"encoding\": \"utf8\",\n" + "        \"compress\": \"raw\",\n" + "        \"format\": \"json\"\n" + "      }\n" + "    }\n" + "  },\n" + "  \"payload\": {\n" + "    \"input\": {\n" + "      \"encoding\": \"utf8\",\n" + "      \"compress\": \"raw\",\n" + "      \"format\": \"plain\",\n" + "      \"status\": 3,\n" + "      \"text\": \"" + getBase64TextData(text) + "\"\n" + "    }\n" + "  }\n" + "}";
    }

    public static String getBase64TextData(String text) {
        return Base64.getEncoder().encodeToString(text.getBytes());
    }

    @SneakyThrows
    public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) {
        URL url = new URL(hostUrl);
        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        // 拼接
        String preStr = "host: " + url.getHost() + "\n" + "date: " + date + "\n" + "POST " + url.getPath() + " HTTP/1.1";
        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));
        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).addQueryParameter("date", date).addQueryParameter("host", url.getHost()).build();
        return httpUrl.toString();
    }

    public static String doPostJson(String url, String json) {
        CloseableHttpClient closeableHttpClient = HttpClients.createDefault();
        CloseableHttpResponse closeableHttpResponse = null;
        String resultString;
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            closeableHttpResponse = closeableHttpClient.execute(httpPost);
            resultString = EntityUtils.toString(closeableHttpResponse.getEntity(), StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("请求失败", e);
            throw new BusinessException("请求失败:" + e.getMessage());
        } finally {
            try {
                if (closeableHttpResponse != null) {
                    closeableHttpResponse.close();
                }
                if (closeableHttpClient != null) {
                    closeableHttpClient.close();
                }
            } catch (Exception e) {
                log.error("请求失败", e);
            }
        }
        return resultString;
    }

    static class JsonParse {
        Header header;
        Payload payload;
        String message;
    }

    static class Header {
        int code;
        String message;
    }

    static class Payload {
        Result result;
    }

    static class Result {
        String text;
    }
}
